도커 레이어 & 네트워크

도커 레이어 개괄

컨테이너의 핵심 기술

이미지

Pasted image 20240705235720.png

레이어 구조

Overlay2

Pasted image 20240706001117.png

실습


전체 디렉토리

Pasted image 20240705141004.png
기본적으로 /var/lib/docker에 데이터들이 존재한다.
Pasted image 20240705161002.png
크기를 보면 대충 overlay2가 가장 크다는 것을 알 수 있을 것이다.

buildkit

도커 buildkit 참조.
S-도커 db 확장자 장애를 보면 알 수 있듯 여기에 있는 데이터 잘못 건드리면 난리나니까 조심하도록 한다.

overlay2

실제 스토리지로 활용되는 디렉터리이다.
말 그대로, 도커를 띄우는데 필요한 모든 데이터가 다 들어있다.
Pasted image 20240705164104.png
이중에서 init이 붙는 녀석은 컨테이너 개수만큼 존재한다.
즉, 컨테이너 생성 시 씌워지는 thin layer라는 것이다.
나머지는.. 뭐 딱 보면 알겠지만 이미지들을 만들 때 쓰이는 레이어들에 대한 디렉토리이다.
Pasted image 20240705181137.png
이중에서 l이라는 디렉토리는 심볼릭 링크를 나타낸다.
여기에는 또다른 해시 값들이 각 레이어들의 실제 내용, diff 디렉토리들을 담고 있다.

이 심볼릭 링크가 어떻게 쓰이는지를 보기 이전에 각 레이어 디렉토리를 살펴본다.
Pasted image 20240705181454.png
내가 띄워둔 컨테이너의 레이어 디렉터리를 들어가보았다.
init은 컨테이너 생성 직전에 생기는 최종 이미지 디렉터리이고, 실제 컨테이너 디렉터리는 init이 떼어진 디렉터리이다.
각 디렉터리에 대한 설명이다.

내부 파일의 생김새를 보면 알 수 있듯, 이 녀석들이 실제 컨테이너의 내부를 구성하는 파일들인 것이다.
Pasted image 20240705181712.png
이 디렉들이 역할은 컨테이너를 inspect해서도 알 수 있다.
이 이미지에서 LowerDir이 엄청 많고, 찾기 어려운 것처럼 보인다.
안 그래도 레이어는 덮어씌워진다 했는데, 왜 그 덮어씌워질 아래 디렉터리가 없는 것이냐!
그것은 lower 파일을 통해서 얻어진다.
Pasted image 20240705233225.png
이게 lower 파일인데, 안 속에 l 디렉의 파일들을 가리키고 있다.
Pasted image 20240705233313.png
이제야 l 디렉의 내부를 볼 타이밍이 왔다.
그 안에는 또 해시된 어떤 심볼릭 링크가 위치하고 있다.
이 심볼릭 링크는 각 레이어의 결과물인 diff를 가리키고 있다.
정리해보자면, 이렇다.
한 레이어는 자신의 lower 파일에 해당하는 것을 참조할 때 이를 통해서 빠르게 레이어를 쌓고 merged 디렉을 만든다.
스스로를 l디렉에 저장되는 해시값 정보를 link 파일에 남기는 것.

왜 굳이 이렇게 해시값을 만들어 l에 저장할까?
아래는 내 견해이다.

Pasted image 20240705183236.png
참고로, 컨테이너가 되지 않은 레이어들은 이렇게 생겼다.
각 레이어가 가진 그 자체의 정보는 전부 diff에 있다.
merged가 된 놈이 없는데, 실제 이미지가 될 놈만 merge가 되면 되니까 그런 듯하다.
아무튼 저렇게 작은 dev, etc단위의 변화가 점차 모여서 하나의 큰 컨테이너를 완성하는 것이다.
committed는 commit 기능을 이야기한다.
현재 컨테이너 상태를 commit 한다는 것은 레이어화를 시킨다는 뜻인데, 말그대로 이 레이어가 commit됐다는 것을 말하는 정도의 의미에 불과하다.
달리 말해, 읽기 전용 상태가 됐다를 보장할 수 있는 녀석이기도 하다.

Pasted image 20240705234026.png
하는 김에 새로 pull을 받아서도 확인해보자
Pasted image 20240705234121.png
보다시피 새로운 레이어가 들어왔는데, 해당 레이어는 스토리지에 잘 들어왔다.
맨 아래 다이제스트는 태그와 관련된 정보이다.
즉, 위에서 본 image쪽의 repository.json 파일에 담겨있고, 저 다이제스트가 어떤 이미지에 해당하는지에 대한 정보도 담겨있다.

image

직관적인 이름..
이미지들에 대한 정보를 담는다.
하지만 아까 봤듯, 실제 데이터는 전부 overlay2라는 디렉에 저장되고, 이 녀석은 빠르게 이미지 정보를 꺼내기 위해 존재하는 녀석 정도이다.
스토리지는 다양할 수 있기 때문에, 내부에 overlay2라는 디렉이 있다.
만약 내가 스토리지 방식을 aufs로 만드는 설정을 했다면 aufs 디렉이 추가됐을 것이다.
Pasted image 20240705161532.png
이게 이미지 디렉 안 속의 정보이다.
기본적으로 이미지의 디렉이 있고, 이미지를 구성하는 레이어들의 정보가 있다.

distribution

Pasted image 20240705164009.png
잠깐 distribution이라는 디렉을 먼저 훑자면, 그냥 데이터를 빠르게 조회할 수 있도록 키값 쌍을 저장해두는 디렉이다.
이름은 저렇게 돼있는데, 직접 만져보니까 v2 -> diff -> digest 관계로 키값을 조회할 수 있었다.
근데 왜 by인걸까? to라고 하는 게 맞지 않나..?
그건 이제 도커 개발자들이 알 만한 내용인 것 같다.

repositories.json

원하는 데이터에 더 빠르게 접근할 수 있도록 또 파일이 있다.
Pasted image 20240705161814.png
기본적으로 빠르게 이미지를 찾을 수 있도록 json이 형성되어 있다.
태그 정보를 찾을 수 있도록 층위가 한 칸 더 들어간다.
이게 중요한 것이, 사용자가 docker pull 등의 이미지와 관련된 동작을 할 때 Digest라면서 표시되는 해시 값이 여기에 나오는 해시값이다.
한 이미지에 대해서도 다양한 태그와 버전이 존재할 수 있으니, 이러한 접근은 매우 합당하다.

imagdb

Pasted image 20240705162231.png
content와 metadata가 나뉘는 이유는 잘 모르겠다.
이것도 개발자한테 물어봐야할 듯.
Pasted image 20240705161427.png
이미지들의 해시 값이 imaged 안에 있다.
해당 해시 파일들을 까보면 이미지를 inspect하는 것과 비슷한 값이 나온다.
Pasted image 20240706011722.png
각각은 파일이고, 이러한 정보를 담고 있다.
여기에는 도커파일을 빌드할 당시의 정보도 담겨 있어, 이미지를 직접 만드는 개발자라면 기본적으로 알아두면 좋을 포인트이다.

layerdb

Pasted image 20240705163045.png
Pasted image 20240705163302.png
그보다 sha256에 더 깊이 들어가보면 레이어들에 대한 정보가 들어있다.
알아보기는 어렵지만, 각 레이어의 정보를 확실히 담고 있다.
가지고 있는 것이 전부 해시 값인 것을 확인할 수 있다.

잠시 정리하자면, images라는 디렉에는 어떤 스토리지를 쓸지에 따라 데이터가 저장된다.
실제 데이터는 해당 스토리지 디렉에 저장될 것이고 여기에는 각 이미지와 레이어의 해시값만 저장되는 장소인 것이다.
빠르게 컨테이너를 실행하고 불러오기 위한 해시테이블이 들어있는 것이다.
Pasted image 20240705163845.png
Pasted image 20240706011941.png
그러한 데이터들은 sha256에, 실제로 컨테이너가 띄워질 때는 mounts 디렉에도 들어가게 된다.

Pasted image 20240705162636.png
컨테이너 inspect를 할 때 레이어로 추정되는 이 녀석들은 무엇인가?
여기에 나오는 해시값은 전부 overlay2 디렉의 해시값이다.
확인해보니까 다 일일히 있더라..

그럼 도대체 이 image라는 디렉은 왜 존재하는 거야?
내 견해는 이렇다.
무거운 overlay2 디렉터리 때문이다.
근데 사용자가 docker ps 등의 명령어를 쉴 새 없이 날려댄다.
그때마다 일일히 디렉터리를 뒤져대는 건 비효율적이라 일종의 캐싱 역할로 각종 정보를 남겨두는것이다.
개인적으로는 도커가 초반에 개발된 이후로 더 효율적인 구조로 바꾸지 못한 잔재로 보이기도 한다.
뭣하러 overlay2에, 여기에 따로따로 캐싱이 존재하나.
containerd가 분리될 정도의 리팩터링을 거칠 수 있었음에도 바꾸지 않았단 것은 오히려 이럴 수밖에 없는 이유가 있었다는 것일 수도 있다.

containers

Pasted image 20240705141239.png
현재 추적되는 컨테이너들에 대한 정보가 담긴다.
몇 가지는 단순하게 알 수 있다.

해결하고 싶었던 궁금증

  1. 어떻게 생겨먹었지?
    1. 유니온 파일시스템
    2. 컨테이너가 생성될 때 마지막 thin layer 생성되어 자유롭게 사용 가능
  2. 이미지 빌드할 때 무슨 일이 발생하지?
    1. 도커파일에 명시된 순서에 따라 overlay2 디렉에 레이어를 저장
    2. 각 레이어는 l 디렉에 키값이 저장되어 빠르게 접근 가능
    3. 마지막 레이어가 완성되면 image 디렉에 관련된 정보를 저장
  3. 그걸로 컨테이너 실행할 땐 무슨 일이 발생하지?
    1. image 디렉에 있는 정보를 토대로 overlay2 디렉에서 참조할 파일을 확보
    2. 그걸 기준으로 컨테이너 초기 디렉을 overlay2에 생성
      1. init이 뒤에 붙은 디렉
    3. 초기 디렉을 통해 최종적인 컨테이너 디렉을 만들어 독립된 프로세스에 할당
      1. 프로세스마다 완성된 형태의 파일시스템을 가지고 있음
  4. 캐싱은 어디에 담기지?
    1. overlay2 디렉에 정보가 있기만 하다면, 그것이 곧 캐싱?
    2. 이게 아직 완벽하지 않다.

실습

보여주고 싶은 것

Pasted image 20240708093747.png

시나리오

참고